<?php

// @formatter:off
/**
 * @file WCTagsHolder.php
 * @author Alejandro Dario Simi
 * @date $Date: 2014-05-04 01:33:52 +0000 (Sun, 04 May 2014) $
 *
 * $Id: WCTagsHolder.php 111 2014-05-04 01:33:52Z daemonraco@gmail.com $
 * $URL: http://wcomix.googlecode.com/svn/trunk/includes/holders/WCTagsHolder.php $
 */
// @formatter:on

/**
 * @class WCTagsHolder This class is a holder for representations of table
 * '%tags', in other words, a holder for WCTag objects.
 */
class WCTagsHolder extends WCHolderGroup implements WCSearchIndexableHolder {
	/**
	 * @var string Class name of the objects to be held.
	 */
	protected $_PropertiesItemClass = "WCTag";
	/**
	 * @var string This is the prefix of every column on the table
	 * '%tags'.
	 */
	protected $_PropertiesPrefix = "tag_";
	/**
	 * @var string This is the name of the table represented by WCTag
	 * objects. In this case, '%tags'.
	 */
	protected $_PropertiesTable = "tags";
	//
	// Public methods.
	/**
	 * @deprecated
	 */
	public function addTagTo(WCTag &$tag, WCComic &$comic) {
		return $this->addTagToComic($tag, $comic);
	}
	/**
	 * This method allows to add a comic to a tag.
	 *
	 * @param WCTag $tag Tag receiving a new member.
	 * @param WCComic $comic Comic to be added.
	 * @return boolean Returns true it was added.
	 */
	public function addTagToComic(WCTag &$tag, WCComic &$comic) {
		//
		// Setting a default value to be returned.
		$out = false;
		//
		// Checking:
		//	- tag is ok.
		//	- comic is ok.
		//	- tag and comic belong to the same group.
		if($tag->ok() && $comic->ok() && $tag->group == $comic->group) {
			//
			// Adding the comic to the tag.
			$out = $tag->addComic($comic);
		}
		//
		// Returning addition result.
		return $out;
	}
	/**
	 * This method allows to add a image to a tag.
	 *
	 * @param WCTag $tag Tag receiving a new member.
	 * @param WCImage $image Image to be added.
	 * @return boolean Returns true it was added.
	 */
	public function addTagToImage(WCTag &$tag, WCImage &$image) {
		//
		// Setting a default value to be returned.
		$out = false;
		//
		// Checking:
		//	- tag is ok.
		//	- image is ok.
		//	- tag and image belong to the same group.
		if($tag->ok() && $image->ok() && $tag->group == $image->group) {
			//
			// Adding the image to the tag.
			$out = $tag->addImage($image);
		}
		//
		// Returning addition result.
		return $out;
	}
	/**
	 * This method allows to add all members of a directory to a tag.
	 *
	 * @param WCTag $tag Tag receiving new members.
	 * @param WCDirectory $directory Directory holding the items to be added.
	 * @return boolean Returns true when all members of the directory were
	 * added.
	 */
	public function addTagToDirectory(WCTag &$tag, WCDirectory &$directory) {
		/** @todo add images behavior */
		//
		// Setting a default value to be returned.
		$out = false;
		//
		// Checking:
		//	- tag is ok.
		//	- directory is ok.
		//	- tag is from the same group than directory.
		if($tag->ok() && $directory->ok() && $tag->group == $directory->group) {
			//
			// Adding the directory to the tag.
			$out = $tag->addDirectory($directory);
		}
		//
		// Returning addition result.
		return $out;
	}
	/**
	 * This method allows to add all members of a tag to another.
	 *
	 * @param WCTag $tag Tag receiving new members.
	 * @param WCTag $tagToAdd Tag holding the items to be added.
	 * @return boolean Returns true when all members were added.
	 */
	public function addTagToTag(WCTag &$tag, WCTag &$tagToAdd) {
		/** @todo add images behavior */
		//
		// Setting a default value to be returned.
		$out = false;
		//
		// Checking:
		//	- origin tag is ok.
		//	- destination tag is ok.
		//	- both tags belong to the same group.
		if($tag->ok() && $tagToAdd->ok() && $tag->group == $tagToAdd->group) {
			//
			// Adding the origin tag's elements.
			$out = $tag->addTag($tagToAdd);
		}
		//
		// Returning addition result.
		return $out;
	}
	/**
	 * @deprecated
	 * This method enforces the existence of special tags on every group.
	 */
	public function createSpecialTags() {
		//
		// Loading global pointers.
		global $wcActiveTagsHolder;
		//
		// Calling true method.
		$wcActiveTagsHolder->createSpecialTags();
	}
	public function notIndexedId() {
		$out = array();
		//
		// Creating the statement to select non indexed tags.
		// @{
		$stmt = null;
		$stmtId = __CLASS__."::".__FUNCTION__."[{$this->_PropertiesTable}]";
		if($this->_db->has($stmtId)) {
			$stmt = $this->_db->get($stmtId);
		} else {
			$query = "select  {$this->_PropertiesPrefix}id as id\n";
			$query .= "from    {$this->_dbprefix}{$this->_PropertiesTable}\n";
			$query .= "where   {$this->_PropertiesPrefix}indexed = 'N'\n";

			$stmt = $this->_db->prepare($stmtId, $query);
		}
		// @}

		if($stmt->execute() && $stmt->rowCount() > 0) {
			foreach($stmt->fetchAll() as $row) {
				$out[] = $row["id"];
			}
		}

		return $out;
	}
	public function searchItemsType() {
		return "TA";
	}
	/**
	 * @deprecated
	 * This method allows to retrieve tags associated with certain group.
	 *
	 * @param WCGroup $group Group associated with all tags to return.
	 * @param boolean $noSpecials When this parameter is true, special tags
	 * won't be brought into the returning list.
	 * @return WCTag[] List of tags.
	 */
	public function tags(WCGroup &$group, $noSpecials = false) {
		/** @fixme something in here smells wrong. '$this->items()' should bring all tags,
		 * even specials, therefore, '$noSpecials' may be having no effect. */
		//
		// Loading global pointers.
		global $wcSpecialTags;
		//
		// Setting a default value to be returned.
		$out = array();
		//	//
		//	// Checking if special tags should be returned.
		//	if(!$noSpecials) {
		//		//
		//		// Searching and adding all special tags.
		//		foreach($wcSpecialTags as $name) {
		//			$tag = $this->itemByName($name, $group);
		//			if($tag) {
		//				$out[] = $tag;
		//			}
		//		}
		//	}
		//
		// Loading the rest of tags.
		$out = array_merge($out, $this->items($group));
		//
		// Sorting generated list.
		uasort($out, "WCTag::NameSort");
		//
		// Returning a list of tags.
		return $out;
	}
	/**
	 * @deprecated
	 */
	public function tagsOf(WCComic &$comic) {
		deprecated();
		return $this->tagsOfComic($comic);
	}
	/**
	 * This method generates a list of tags based on a comic.
	 *
	 * @param WCComic $comic Comic to use as filter.
	 * @return WCTag[] List of tags where the comic is included.
	 */
	public function tagsOfComic(WCComic &$comic) {
		//
		// Setting a default value to be returned.
		$out = array();
		//
		// Creating a statement for tags of a comic.
		// @{
		$stmt = null;
		$stmtId = __CLASS__."::".__FUNCTION__;
		if($this->_db->has($stmtId)) {
			$stmt = $this->_db->get($stmtId);
		} else {
			$query = "select  distinct mem_tag\n";
			$query .= "from    {$this->_dbprefix}tag_comics\n";
			$query .= "where   mem_group = :group\n";
			$query .= " and    mem_comic = :comic";

			$stmt = $this->_db->prepare($stmtId, $query);
		}
		// @}
		//
		// Building database parameters.
		$params = array(
			":group" => $comic->group,
			":comic" => $comic->id
		);
		//
		// Requesting tag ids.
		if($stmt->execute($params)) {
			//
			// Creating a shortcut for comic's group.
			$group = $comic->group();
			//
			// Walking over every result and creating a list of tags
			// with them.
			foreach($stmt->fetchAll() as $row) {
				$tag = $this->item($row["mem_tag"], $group);
				if($tag) {
					$out[] = $tag;
				}
			}
		}
		//
		// Sorting generated list.
		uasort($out, "WCTag::NameSort");
		//
		// Returning a list of tags.
		return $out;
	}
	/**
	 * This method generates a list of tags based on a image.
	 *
	 * @param WCImage $image Image to use as filter.
	 * @return WCTag[] List of tags where the image is included.
	 */
	public function tagsOfImage(WCImage &$image) {
		//
		// Setting a default value to be returned.
		$out = array();
		//
		// Creating a statement for tags of a image.
		// @{
		$stmt = null;
		$stmtId = __CLASS__."::".__FUNCTION__;
		if($this->_db->has($stmtId)) {
			$stmt = $this->_db->get($stmtId);
		} else {
			$query = "select  distinct mem_tag\n";
			$query .= "from    {$this->_dbprefix}tag_images\n";
			$query .= "where   mem_group = :group\n";
			$query .= " and    mem_image = :image";

			$stmt = $this->_db->prepare($stmtId, $query);
		}
		// @}
		//
		// Building database parameters.
		$params = array(
			":group" => $image->group,
			":image" => $image->id
		);
		//
		// Requesting tag ids.
		if($stmt->execute($params)) {
			//
			// Creating a shortcut for image's group.
			$group = $image->group();
			//
			// Walking over every result and creating a list of tags
			// with them.
			foreach($stmt->fetchAll() as $row) {
				$tag = $this->item($row["mem_tag"], $group);
				if($tag) {
					$out[] = $tag;
				}
			}
		}
		//
		// Sorting generated list.
		uasort($out, "WCTag::NameSort");
		//
		// Returning a list of tags.
		return $out;
	}
	/**
	 * This method generates a list of tags based on a directory.
	 *
	 * @param WCDirectory $directory Directory to use as filter.
	 * @return WCTag[] List of tags where the directory's elements are included.
	 */
	public function tagsOfDirectory(WCDirectory &$directory) {
		//
		// Setting a default value to be returned.
		$out = array();
		//
		// Creating a statement for tags of a directory.
		// @{
		$stmt = null;
		$stmtId = __CLASS__."::".__FUNCTION__;
		if($this->_db->has($stmtId)) {
			$stmt = $this->_db->get($stmtId);
		} else {
			$query = "select  distinct mem_tag\n";
			$query .= "from    ((\n";
			$query .= "                select  mem_tag\n";
			$query .= "                from    {$this->_dbprefix}tag_comics\n";
			$query .= "                                inner join {$this->_dbprefix}comics\n";
			$query .= "                                        on (cmc_id = mem_comic)\n";
			$query .= "                where   mem_group     = :group\n";
			$query .= "                 and    cmc_directory = :directory\n";
			$query .= "        ) union all (\n";
			$query .= "                select  mem_tag\n";
			$query .= "                from    {$this->_dbprefix}tag_images\n";
			$query .= "                                inner join {$this->_dbprefix}images\n";
			$query .= "                                        on (img_id = mem_image)\n";
			$query .= "                where   mem_group     = :group\n";
			$query .= "                 and    img_directory = :directory\n";
			$query .= "        )) members\n";

			$stmt = $this->_db->prepare($stmtId, $query);
		}
		// @}
		//
		// Building database parameters.
		$params = array(
			":group" => $directory->group,
			":directory" => $directory->id
		);
		//
		// Requesting tag ids.
		if($stmt->execute($params)) {
			//
			// Creating a shortcut for directory's group.
			$group = $directory->group();
			//
			// Walking over every result and creating a list of tags
			// with them.
			foreach($stmt->fetchAll() as $row) {
				$tag = $this->item($row["mem_tag"], $group);
				if($tag) {
					$out[] = $tag;
				}
			}
		}
		//
		// Sorting generated list.
		uasort($out, "WCTag::NameSort");
		//
		// Returning a list of tags.
		return $out;
	}
	/**
	 * This method generates a list of tags based on a tag.
	 *
	 * @param WCTag $tag Tag to use as filter.
	 * @return WCTag[] List of tags where the tag's elements are included.
	 */
	public function tagsOfTag(WCTag &$tag) {
		//
		// Setting a default value to be returned.
		$out = array();
		//
		// Creating a statement for tags of a tag.
		// @{
		$stmt = null;
		$stmtId = __CLASS__."::".__FUNCTION__;
		if($this->_db->has($stmtId)) {
			$stmt = $this->_db->get($stmtId);
		} else {
			$query = "select  distinct tci.mem_tag as id\n";
			$query .= "from    ((\n";
			$query .= "                select  memc.mem_tag as mem_tag\n";
			$query .= "                from    wc_tag_comics as memc\n";
			$query .= "                                inner join (\n";
			$query .= "                                        select mem_comic\n";
			$query .= "                                        from    wc_tag_comics\n";
			$query .= "                                        where   mem_group = :group\n";
			$query .= "                                         and mem_tag = :tag) as tmp\n";
			$query .= "                                                on (tmp.mem_comic = memc.mem_comic)\n";
			$query .= "                where   memc.mem_group =  :group\n";
			$query .= "                 and    memc.mem_tag   <> :tag\n";
			$query .= "        ) union all (\n";
			$query .= "                select  memi.mem_tag as mem_tag\n";
			$query .= "                from    wc_tag_images as memi\n";
			$query .= "                                inner join (\n";
			$query .= "                                        select mem_image\n";
			$query .= "                                        from    wc_tag_images\n";
			$query .= "                                        where   mem_group = :group\n";
			$query .= "                                         and mem_tag = :tag) as tmp\n";
			$query .= "                                                on (tmp.mem_image = memi.mem_image)\n";
			$query .= "                where   memi.mem_group =  :group\n";
			$query .= "                 and    memi.mem_tag   <> :tag\n";
			$query .= "        )) as tci";

			$stmt = $this->_db->prepare($stmtId, $query);
		}
		// @}
		//
		// Building database parameters.
		$params = array(
			":group" => $tag->group,
			":tag" => $tag->id
		);
		//
		// Requesting tag ids.
		if($stmt->execute($params)) {
			//
			// Walking over every result and creating a list of tags
			// with them.
			foreach($stmt->fetchAll() as $row) {
				$tag = $this->item($row["id"]);
				if($tag) {
					$out[] = $tag;
				}
			}
		}
		//
		// Sorting generated list.
		uasort($out, "WCTag::NameSort");
		//
		// Returning a list of tags.
		return $out;
	}
	/**
	 * This method generates a list of tags based on a keyword. In other
	 * words, it looks for tags with a name like '%keyword%'.
	 * Search is a case insensitive on.
	 *
	 * @param string $keyword Word to use as filter.
	 * @param WCGroup $group Where of found tags.
	 * @return WCTag[] List of tags where the tag's elements are included.
	 */
	public function tagsLike($keyword, WCGroup &$group) {
		//
		// Setting a default value to be returned.
		$out = array();
		//
		// Creating a statement for tags with a name like the keywords.
		// @{
		$stmt = null;
		$stmtId = __CLASS__."::".__FUNCTION__;
		if($this->_db->has($stmtId)) {
			$stmt = $this->_db->get($stmtId);
		} else {
			$query = "select  *\n";
			$query .= "from    {$this->_dbprefix}tags\n";
			$query .= "where   tag_group = :group\n";
			$query .= " and    lower(tag_name) like :filter\n";

			$stmt = $this->_db->prepare($stmtId, $query);
		}
		// @}
		//
		// Building database parameters.
		$params = array(
			":group" => $group->id,
			":filter" => "%".strtolower($keyword)."%"
		);
		//
		// Requesting tag ids.
		if($stmt->execute($params)) {
			//
			// Walking over every result and creating a list of tags
			// with them.
			foreach($stmt->fetchAll() as $row) {
				$tag = $this->item($row["tag_id"], $group);
				$out[] = $tag;
			}
		}
		//
		// Sorting generated list.
		uasort($out, "WCTag::NameSort");
		//
		// Returning a list of tags.
		return $out;
	}
}
